// deribit crawler


const jsdom = require("jsdom");
const https = require('https');
const WebSocket = require("websocket").w3cwebsocket;
const deribitApi = require("./deribit/main_app.js");
const n2oApi = require("./deribit/n2o.js");
const SQLite = require("better-sqlite-pool")

var JSDOM = jsdom.JSDOM;
var {deribit, initDeribit, pingDeribit, reinitDeribit, optTS, updOpt, updOptSelect, setPlatformLocked, optViewInitBegin, stopLoadSpin, updLastOpts, prepLastOpts, appLastOptsCall, appLastOptsPut, scrollTradesCall, scrollTradesPut} = deribitApi
var {atom, bin, enc, tuple, dec, utf8_fromByteArray, utf8_toByteArray, validateSources, validateMin, validateLength, qi, qn, qs} = n2oApi


const debug = 1
const debug_exception = 0


function log_state(data) { debug && console.debug("[ws] - ", data) }
function log_send(data) { debug && console.debug("[send] - ", data) }
function log_recv(data) { debug && console.debug("[recv] - ", data) }

var dom = new JSDOM('');
globalThis.window = dom.window;
globalThis.document = dom.window.document;
var $ = jQuery = require('jquery')(window);
globalThis.$ = $
globalThis.$IR = function(data){}
globalThis.$z = updOpt
globalThis.log_state = log_state
globalThis.log_send = log_send
globalThis.log_recv = log_recv
globalThis.debug = debug
window.deribit = deribit


var dbPool = new SQLite.Pool('./sql/deribit.db', 16)
globalThis.dbPool = dbPool

dbPool.onConnectionCreated = function(conn){
    // ATTACH DATABASE `log.db` as `log`;
    debug && console.log('[db] - sqlite connected!');
}


function preload(){
    const transition_ptn = /var transition = (\{[\s\S]+?\})/g;
    const pid_ptn = /pid:\s*('[\s\S]+?')/g;

    return new Promise((resolve) => {
        try{
            https.get("https://www.deribit.com/main#/options?tab=all", (res) => {
                const {statusCode} = res;
                if (statusCode != 200) {
                    console.error("status code error! " + statusCode);
                    res.resume();
                    var e = new Error('status code error!' + statusCode)
                    throw e
                }
    
                let html = ""
                res.on("data", (data) => {
                    html += data;
                });
                res.on("end", () => {
                    transition = transition_ptn.exec(html)[1];
                    if (null != transition){
                        pid = pid_ptn.exec(transition)[1].replace(/'/g, "");
                        debug && console.debug(pid);
    
                        if (null != pid) resolve(pid);
                        else throw new Error("pid null.");
                    } else {
                        throw new Error("transition not match.");
                    }
                    
                });
    
            });
        } catch(e) {
            console.error(e);
            throw e;
        }
    });
}


function start_main(pid){
    var url = "wss://www.deribit.com/ws/main";
    var BEAT_TIME = 10000;

    return new Promise((resolve) => {
        try{
            var ws = new WebSocket(url)
    
            ws.onopen = (evt) => {
                log_state("Connect!");
                
                setInterval(function(){
                    log_send('PING');
                    ws.send('PING');
                }, BEAT_TIME);

                
                ws.send("N2O," + pid);

                deribitApi.pingDeribit();

                setTimeout(deribitApi.scrollTradesCall, 0);
                setTimeout(deribitApi.scrollTradesPut, 3); 
            };
    
            ws.onclose = (evt) => {
                log_state("Closed!");

                resolve();
            };
    
            ws.onmessage = (evt) => {
                // log_recv(evt.data);

                var msg;
                try{
                    msg = JSON.parse(evt.data)
                } catch(e) {
                    log_recv(evt.data);
                    return;
                }
                try{
                    if (msg.eval){
                        // log_recv(msg.eval)
                        // 执行得到的数据
                        eval(msg.eval);
                    }
                } catch(e) {
                    debug_exception && debug && console.warn(e);
                }

            };
    
            ws.onerror = (evt) => {
                log_state("Error!");
                resolve();
            };
            
        } catch(e) {
            console.error(e);
            throw e
        } 
    });
}




/**
 * main enter.
 * 
 **/


 async function run(){
    let pid = await preload();
    await start_main(pid);

    if (dbPool){
        dbPool.close();
    }

    console.log("Quit!")
 }


 run();




